﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Diagnostics;
using Microsoft.Win32;
using System.Windows.Forms;
/// <summary>
/// 键盘钩子  
/// @author yp
/// @version 2017-10-16
/// </summary>
namespace brow
{
    class KeyBoardHook
    {
        /// <summary>
        /// 常量   钩子类型  键盘
        /// </summary>
        private const int WH_KEYBOARD_LL = 13; 

        //键盘处理事件委托 ,当捕获键盘输入时调用定义该委托的方法. 
        private  delegate int HookHandle(int nCode, int wParam, IntPtr lParam);


        //客户端键盘处理事件 
        public delegate void ProcessKeyHandle(HookStruct param, out bool handle);

        //接收SetWindowsHookEx返回值 
        private static int _hHookValue = 0;


        //Hook结构 
        [StructLayout(LayoutKind.Sequential)]
        public class HookStruct
        {
            public int vkCode;
            public int scanCode;
            public int flags;
            public int time;
            public int dwExtraInfo;
        }


        //构造器 
        public KeyBoardHook() { }

        /// <summary>
        /// 设置钩子 
        /// </summary>
        /// <param name="idHook">钩子类型</param> 
        /// <param name="lpfn">钩子函数入口地址 发起LauncherHook</param>
        /// <param name="hMod">钩子函数所在的模块句柄</param>
        /// <param name="dwThreadId">钩子相关函数ID 0 表示全局</param>
        /// <returns></returns>
        [DllImport("user32.dll")]
        private static extern int SetWindowsHookEx(int idHook, HookHandle lpfn, IntPtr hMod, int threadId);



        //取消钩子 
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        private static extern bool UnhookWindowsHookEx(int idHook);



        //调用下一个钩子 
        [DllImport("user32.dll")]
        private static extern int CallNextHookEx(int idHook, int nCode, int wParam, IntPtr lParam);




        //获取模块句柄
        [DllImport("kernel32.dll")]
        private static extern IntPtr GetModuleHandle(string name);

        /// <summary>
        // 钩子函数模块句柄
        /// </summary>
        private static IntPtr _hookWindowPtr = IntPtr.Zero;

        /// <summary>
        /// 外部调用的键盘处理事件
        /// </summary>
        private static ProcessKeyHandle _clientMethod = null;

        /// <summary>
        ///  初始化    设置当前窗口为 键盘钩子模块句柄
        /// </summary>
        public  void init(ProcessKeyHandle clientMethod)
        {
            _hookWindowPtr = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);
            Console.WriteLine("模块名"+ Process.GetCurrentProcess().MainModule.ModuleName);
            _clientMethod = clientMethod;
        }





        //设置静态变量  防止GC 回收
        private static HookHandle _HookHandle = new HookHandle(OnHookProc);

        /// <summary> 
        /// 安装勾子 
        /// </summary> 
        /// <param name="hookProcess">外部调用的键盘处理事件</param> 
        public void InstallHook()
        {
           
            if (_hHookValue == 0)
            {
                _hHookValue = SetWindowsHookEx(WH_KEYBOARD_LL, _HookHandle, _hookWindowPtr, 0);
                //如果设置钩子失败. 
                if (_hHookValue == 0) UninstallHook();
            }
           
           
        }

        /// <summary>
        /// 取消钩子事件 
        /// </summary>
        public void UninstallHook()
        {
            if (_hHookValue != 0)
            {
                bool ret = UnhookWindowsHookEx(_hHookValue);
                if (ret) _hHookValue = 0;
            }
        }




        //钩子事件内部调用,调用_clientMethod方法转发到客户端应用。 
        private static int OnHookProc(int nCode, int wParam, IntPtr lParam)
        {
            if (nCode >= 0) {
                //转换结构 
                HookStruct hookStruct = (HookStruct)Marshal.PtrToStructure(lParam, typeof(HookStruct));
                if (_clientMethod != null){
                    bool handle = false;
                    //调用客户提供的事件处理程序。 
                    _clientMethod(hookStruct, out handle);
                    if (handle) return 1; //1:表示拦截键盘,return 退出 
                }
            }
            return CallNextHookEx(_hHookValue, nCode, wParam, lParam);
        }







    }
}
